﻿using Microsoft.Phone.Controls;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media.Animation;
using Windows.UI.ViewManagement;
using Windows8Accelerator.Core.Xaml.Commands;
using Windows8Accelerator.Core.Xaml.Helpers;

namespace Windows8Accelerator.Core.Xaml.Controls
{
    [TemplatePart(Name="root", Type=typeof(Panel))]
    [TemplatePart(Name = "ProgressBar", Type = typeof(ProgressBar))]
    public class SuperSilhouette : ContentControl
    {
        private string UniqueName = Guid.NewGuid().ToString();

        public SuperSilhouette()
        {
            DefaultStyleKey = typeof(SuperSilhouette);
            Loaded += SuperSilhouette_Loaded;
            Unloaded += SuperSilhouette_Unloaded;
            BackButtonCommand = new DelegateCommand((o) =>
            {
                AppHelperBase.Instance.NavigateBack();
            },
            (o) => {
                return AppHelperBase.Instance.CanNavigateBack;
            }
            );
        }

        void SuperSilhouette_Unloaded(object sender, RoutedEventArgs e)
        {
            AppHelper.CurrentPage.OrientationChanged -= CurrentPage_OrientationChanged;
        }

        void CurrentPage_OrientationChanged(object sender, OrientationChangedEventArgs e)
        {
            UpdateViewStyle();
        }

        void SuperSilhouette_Loaded(object sender, RoutedEventArgs e)
        {
            if (AppHelper.CurrentPage != null)
                AppHelper.CurrentPage.OrientationChanged += CurrentPage_OrientationChanged;
        }

        private void UpdateHeaderItem()
        {
            HeaderItem = new SuperSilhouetteHeaderItem()
            {
                BackButtonCommand = BackButtonCommand,
            };
            BindingOperations.SetBinding(
                HeaderItem,
                SuperSilhouetteHeaderItem.BackButtonStyleProperty,
                new Binding() { Path = new PropertyPath("DynamicBackButtonStyle"), Source = this });
            BindingOperations.SetBinding(
                HeaderItem,
                SuperSilhouetteHeaderItem.ContentProperty,
                new Binding() { Path = new PropertyPath("HeaderSource"), Source = this });
            BindingOperations.SetBinding(
                HeaderItem,
                SuperSilhouetteHeaderItem.PageTitleStyleProperty,
                new Binding() { Path = new PropertyPath("DynamicPageTitleStyle"), Source = this });
        }

        public ProgressBar _ProgressBar;
        public ProgressBar ProgressBar { get {
            return _ProgressBar;
        } }

        ICommand BackButtonCommand;



        public int ContentRow
        {
            get { return (int)GetValue(ContentRowProperty); }
            set { SetValue(ContentRowProperty, value); }
        }
        public static readonly DependencyProperty ContentRowProperty =
            DependencyProperty.Register("ContentRow", typeof(int), typeof(SuperSilhouette), new PropertyMetadata(1));

        public int ContentRowSpan
        {
            get { return (int)GetValue(ContentRowSpanProperty); }
            set { SetValue(ContentRowSpanProperty, value); }
        }
        public static readonly DependencyProperty ContentRowSpanProperty =
            DependencyProperty.Register("ContentRowSpan", typeof(int), typeof(SuperSilhouette), new PropertyMetadata(1));

        public Style ProgressBarStyle
        {
            get { return (Style)GetValue(ProgressBarStyleProperty); }
            set { SetValue(ProgressBarStyleProperty, value); }
        }
        public static readonly DependencyProperty ProgressBarStyleProperty =
            DependencyProperty.Register("ProgressBarStyle", typeof(Style), typeof(SuperSilhouette), new PropertyMetadata(null));        

        public Style FullScreenLandscapePageTitleStyle
        {
            get { return (Style)GetValue(FullScreenLandscapePageTitleStyleProperty); }
            set { SetValue(FullScreenLandscapePageTitleStyleProperty, value); UpdateViewStyle(); }
        }
        public static readonly DependencyProperty FullScreenLandscapePageTitleStyleProperty =
            DependencyProperty.Register("FullScreenLandscapePageTitleStyle", typeof(Style), typeof(SuperSilhouette), new PropertyMetadata(null));

        public Style FullScreenPortraitPageTitleStyle
        {
            get { return (Style)GetValue(FullScreenPortraitPageTitleStyleProperty); }
            set { SetValue(FullScreenPortraitPageTitleStyleProperty, value); UpdateViewStyle(); }
        }
        public static readonly DependencyProperty FullScreenPortraitPageTitleStyleProperty =
            DependencyProperty.Register("FullScreenPortraitPageTitleStyle", typeof(Style), typeof(SuperSilhouette), new PropertyMetadata(null));

        public Style FilledPageTitleStyle
        {
            get { return (Style)GetValue(FilledPageTitleStyleProperty); }
            set { SetValue(FilledPageTitleStyleProperty, value); UpdateViewStyle(); }
        }
        public static readonly DependencyProperty FilledPageTitleStyleProperty =
            DependencyProperty.Register("FilledPageTitleStyle", typeof(Style), typeof(SuperSilhouette), new PropertyMetadata(null));

        public Style SnappedPageTitleStyle
        {
            get { return (Style)GetValue(SnappedPageTitleStyleProperty); }
            set { SetValue(SnappedPageTitleStyleProperty, value); UpdateViewStyle(); }
        }
        public static readonly DependencyProperty SnappedPageTitleStyleProperty =
            DependencyProperty.Register("SnappedPageTitleStyle", typeof(Style), typeof(SuperSilhouette), new PropertyMetadata(null));

        public Style DynamicPageTitleStyle
        {
            get { return (Style)GetValue(DynamicPageTitleStyleProperty); }
            set 
            { 
                SetValue(DynamicPageTitleStyleProperty, value);
                UpdateHeaderItem();
            }
        }
        public static readonly DependencyProperty DynamicPageTitleStyleProperty =
            DependencyProperty.Register("DynamicPageTitleStyle", typeof(Style), typeof(SuperSilhouette), new PropertyMetadata(null));

        public DataTemplate DynamicHeaderTemplate
        {
            get { return (DataTemplate)GetValue(DynamicHeaderTemplateProperty); }
            set { SetValue(DynamicHeaderTemplateProperty, value); }
        }
        public static readonly DependencyProperty DynamicHeaderTemplateProperty =
            DependencyProperty.Register("DynamicHeaderTemplate", typeof(DataTemplate), typeof(SuperSilhouette), new PropertyMetadata(null));

        public DataTemplate FullScreenLandscapeHeaderTemplate
        {
            get { return (DataTemplate)GetValue(FullScreenLandscapeHeaderTemplateProperty); }
            set { SetValue(FullScreenLandscapeHeaderTemplateProperty, value); }
        }
        public static readonly DependencyProperty FullScreenLandscapeHeaderTemplateProperty =
            DependencyProperty.Register("FullScreenLandscapeHeaderTemplate", typeof(DataTemplate), typeof(SuperSilhouette), new PropertyMetadata(null));

        public DataTemplate FullScreenPortraitHeaderTemplate
        {
            get { return (DataTemplate)GetValue(FullScreenPortraitHeaderTemplateProperty); }
            set { SetValue(FullScreenPortraitHeaderTemplateProperty, value); }
        }
        public static readonly DependencyProperty FullScreenPortraitHeaderTemplateProperty =
            DependencyProperty.Register("FullScreenPortraitHeaderTemplate", typeof(DataTemplate), typeof(SuperSilhouette), new PropertyMetadata(null));

        public DataTemplate FilledHeaderTemplate
        {
            get { return (DataTemplate)GetValue(FilledHeaderTemplateProperty); }
            set { SetValue(FilledHeaderTemplateProperty, value); }
        }
        public static readonly DependencyProperty FilledHeaderTemplateProperty =
            DependencyProperty.Register("FilledHeaderTemplate", typeof(DataTemplate), typeof(SuperSilhouette), new PropertyMetadata(null));

        public DataTemplate SnappedHeaderTemplate
        {
            get { return (DataTemplate)GetValue(SnappedHeaderTemplateProperty); }
            set { SetValue(SnappedHeaderTemplateProperty, value); }
        }
        public static readonly DependencyProperty SnappedHeaderTemplateProperty =
            DependencyProperty.Register("SnappedHeaderTemplate", typeof(DataTemplate), typeof(SuperSilhouette), new PropertyMetadata(null));

        public object HeaderSource
        {
            get { return (object)GetValue(HeaderSourceProperty); }
            set { 
                SetValue(HeaderSourceProperty, value);
                UpdateHeaderItem();
            }
        }
        public static readonly DependencyProperty HeaderSourceProperty =
            DependencyProperty.Register("HeaderSource", typeof(object), typeof(SuperSilhouette), new PropertyMetadata(null));

        public SuperSilhouetteHeaderItem HeaderItem
        {
            get { return (SuperSilhouetteHeaderItem)GetValue(HeaderItemProperty); }
            private set { SetValue(HeaderItemProperty, value); }
        }
        public static readonly DependencyProperty HeaderItemProperty =
            DependencyProperty.Register("HeaderItem", typeof(SuperSilhouetteHeaderItem), typeof(SuperSilhouette), new PropertyMetadata(null));

        public Style FullScreenLandscapeBackButtonStyle
        {
            get { return (Style)GetValue(FullScreenLandscapeBackButtonStyleProperty); }
            set { SetValue(FullScreenLandscapeBackButtonStyleProperty, value); UpdateViewStyle(); }
        }
        public static readonly DependencyProperty FullScreenLandscapeBackButtonStyleProperty =
            DependencyProperty.Register("FullScreenLandscapeBackButtonStyle", typeof(Style), typeof(SuperSilhouette), new PropertyMetadata(null));

        public Style FullScreenPortraitBackButtonStyle
        {
            get { return (Style)GetValue(FullScreenPortraitBackButtonStyleProperty); }
            set { SetValue(FullScreenPortraitBackButtonStyleProperty, value); UpdateViewStyle(); }
        }
        public static readonly DependencyProperty FullScreenPortraitBackButtonStyleProperty =
            DependencyProperty.Register("FullScreenPortraitBackButtonStyle", typeof(Style), typeof(SuperSilhouette), new PropertyMetadata(null));

        public Style FilledBackButtonStyle
        {
            get { return (Style)GetValue(FilledBackButtonStyleProperty); }
            set { SetValue(FilledBackButtonStyleProperty, value); UpdateViewStyle(); }
        }
        public static readonly DependencyProperty FilledBackButtonStyleProperty =
            DependencyProperty.Register("FilledBackButtonStyle", typeof(Style), typeof(SuperSilhouette), new PropertyMetadata(null));

        public Style SnappedBackButtonStyle
        {
            get { return (Style)GetValue(SnappedBackButtonStyleProperty); }
            set { SetValue(SnappedBackButtonStyleProperty, value); UpdateViewStyle(); }
        }
        public static readonly DependencyProperty SnappedBackButtonStyleProperty =
            DependencyProperty.Register("SnappedBackButtonStyle", typeof(Style), typeof(SuperSilhouette), new PropertyMetadata(null));

        public Style DynamicBackButtonStyle
        {
            get { return (Style)GetValue(DynamicBackButtonStyleProperty); }
            set { 
                SetValue(DynamicBackButtonStyleProperty, value);
                UpdateHeaderItem();
            }
        }
        public static readonly DependencyProperty DynamicBackButtonStyleProperty =
            DependencyProperty.Register("DynamicBackButtonStyle", typeof(Style), typeof(SuperSilhouette), new PropertyMetadata(null));

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            UpdateSetters();

            HeaderRowDefinition = GetTemplateChild("HeaderRowDefinition") as RowDefinition;

            _ProgressBar = GetTemplateChild("ProgressBar") as ProgressBar;
            if (_ProgressBar != null)
            {
                _ProgressBar.SetBinding(ProgressBar.VisibilityProperty, new Binding() { 
                    Source = ProgressBarManager.BindingSource,
                    Path = new PropertyPath("IsVisible"),
                    Converter = new Converters.BooleanToVisibilityConverter(),
                });
            }

            var root = GetTemplateChild("root") as Panel;
            if (root != null)
            {
                VisualStateSnapped = new VisualState();
                VisualStateSnapped.SetValue(FrameworkElement.NameProperty, "Snapped" + UniqueName);
                VisualStateSnapped.Storyboard = SnappedStoryboard;

                VisualStateFullScreenLandscape = new VisualState();
                VisualStateFullScreenLandscape.SetValue(FrameworkElement.NameProperty, "FullScreenLandscape" + UniqueName);

                var vsGroup = new VisualStateGroup();
                vsGroup.States.Add(VisualStateFullScreenLandscape);
                vsGroup.States.Add(VisualStateSnapped);
                var visualStateGroups = VisualStateManager.GetVisualStateGroups(root);
                if (visualStateGroups != null)
                {
                    visualStateGroups.Add(vsGroup);
                }
                UpdateViewStyle();
            }
        }

        private void UpdateSetters()
        {
            UpdateSnappedProperties();
        }

        void WindowsSizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e)
        {
            if (PreviousApplicationViewMode != AppHelperBase.Instance.ApplicationViewMode)
            {
                UpdateViewStyle();
            }
        }

        private void UpdateViewStyle()
        {
            GridLength headerRowDefinitionHeight;
            var applicationViewState = AppHelperBase.Instance.ApplicationViewMode;
            PreviousApplicationViewMode = applicationViewState;
            switch (applicationViewState)
            {
                case ApplicationViewMode.Filled:
                    DynamicBackButtonStyle = FilledBackButtonStyle ?? FullScreenLandscapeBackButtonStyle;
                    DynamicPageTitleStyle = FilledPageTitleStyle ?? FullScreenLandscapePageTitleStyle;
                    DynamicHeaderTemplate = FilledHeaderTemplate ?? FullScreenLandscapeHeaderTemplate;
                    headerRowDefinitionHeight = new GridLength(!double.IsNaN(FilledHeaderRowHeight) ? FilledHeaderRowHeight : FullScreenLandscapeHeaderRowHeight);
                    break;
                case ApplicationViewMode.Landscape:
                default:
                    DynamicBackButtonStyle = FullScreenLandscapeBackButtonStyle;
                    DynamicPageTitleStyle = FullScreenLandscapePageTitleStyle;
                    headerRowDefinitionHeight = new GridLength(FullScreenLandscapeHeaderRowHeight);
                    DynamicHeaderTemplate = FullScreenLandscapeHeaderTemplate;
                    break;
                case ApplicationViewMode.Portrait:
                    DynamicBackButtonStyle = FullScreenPortraitBackButtonStyle ?? FullScreenLandscapeBackButtonStyle;
                    DynamicPageTitleStyle = FullScreenPortraitPageTitleStyle ?? FullScreenLandscapePageTitleStyle;
                    headerRowDefinitionHeight = new GridLength(!double.IsNaN(FullScreenPortraitHeaderRowHeight) ? FullScreenPortraitHeaderRowHeight : FullScreenLandscapeHeaderRowHeight);
                    DynamicHeaderTemplate = FullScreenPortraitHeaderTemplate ?? FullScreenLandscapeHeaderTemplate;
                    break;
                case ApplicationViewMode.Snapped:
                    DynamicBackButtonStyle = SnappedBackButtonStyle ?? FullScreenLandscapeBackButtonStyle;
                    DynamicPageTitleStyle = SnappedPageTitleStyle ?? FullScreenLandscapePageTitleStyle;
                    headerRowDefinitionHeight = new GridLength(!double.IsNaN(SnappedHeaderRowHeight) ? SnappedHeaderRowHeight : FullScreenLandscapeHeaderRowHeight);
                    DynamicHeaderTemplate = SnappedHeaderTemplate ?? FullScreenLandscapeHeaderTemplate;
                    break;
            }

            if (HeaderRowDefinition != null)
                HeaderRowDefinition.Height = headerRowDefinitionHeight;

            //TODO: Tratar todos os ViewStates
            if (applicationViewState == ApplicationViewMode.Filled || applicationViewState == ApplicationViewMode.Portrait)
                applicationViewState = ApplicationViewMode.Landscape;
            VisualStateManager.GoToState(this, applicationViewState.ToString() + UniqueName, false);
        }

        public double FullScreenLandscapeHeaderRowHeight
        {
            get { return (double)GetValue(FullScreenLandscapeHeaderRowHeightProperty); }
            set { SetValue(FullScreenLandscapeHeaderRowHeightProperty, value); UpdateViewStyle(); }
        }
        public static readonly DependencyProperty FullScreenLandscapeHeaderRowHeightProperty =
            DependencyProperty.Register("FullScreenLandscapeHeaderRowHeight", typeof(double), typeof(SuperSilhouette), new PropertyMetadata(default(double)));

        public double FullScreenPortraitHeaderRowHeight
        {
            get { return (double)GetValue(FullScreenPortraitHeaderRowHeightProperty); }
            set { SetValue(FullScreenPortraitHeaderRowHeightProperty, value); UpdateViewStyle(); }
        }
        public static readonly DependencyProperty FullScreenPortraitHeaderRowHeightProperty =
            DependencyProperty.Register("FullScreenPortraitHeaderRowHeight", typeof(double), typeof(SuperSilhouette), new PropertyMetadata(double.NaN));

        public double FilledHeaderRowHeight
        {
            get { return (double)GetValue(FilledHeaderRowHeightProperty); }
            set { SetValue(FilledHeaderRowHeightProperty, value); UpdateViewStyle(); }
        }
        public static readonly DependencyProperty FilledHeaderRowHeightProperty =
            DependencyProperty.Register("FilledHeaderRowHeight", typeof(double), typeof(SuperSilhouette), new PropertyMetadata(double.NaN));

        public double SnappedHeaderRowHeight
        {
            get { return (double)GetValue(SnappedHeaderRowHeightProperty); }
            set { SetValue(SnappedHeaderRowHeightProperty, value); UpdateViewStyle(); }
        }
        public static readonly DependencyProperty SnappedHeaderRowHeightProperty =
            DependencyProperty.Register("SnappedHeaderRowHeight", typeof(double), typeof(SuperSilhouette), new PropertyMetadata(default(double)));

        public RowDefinition HeaderRowDefinition { get; set; }


        private Storyboard _SnappedStoryboard;
        public Storyboard SnappedStoryboard
        {
            get { return _SnappedStoryboard; }
            set 
            { 
                _SnappedStoryboard = value;
                if (VisualStateSnapped != null)
                    VisualStateSnapped.Storyboard = value;
            }
        }

        private Storyboard _FullScreenLandscapeStoryboard;
        public Storyboard FullScreenLandscapeStoryboard
        {
            get { return _FullScreenLandscapeStoryboard; }
            set
            {
                _FullScreenLandscapeStoryboard = value;
                if (VisualStateFullScreenLandscape != null)
                    VisualStateFullScreenLandscape.Storyboard = value;
            }
        }

        private VisualState VisualStateSnapped;

        private VisualState VisualStateFullScreenLandscape;

        private PropertySetters _SnappedProperties;
        private ApplicationViewMode PreviousApplicationViewMode;

        public PropertySetters SnappedProperties
        {
            get { return _SnappedProperties; }
            set 
            { 
                _SnappedProperties = value;
                UpdateSnappedProperties();
            }
        }

        private void UpdateSnappedProperties()
        {
            if (_SnappedProperties != null)
            {
                if (SnappedStoryboard == null)
                    SnappedStoryboard = new Storyboard();

                AddSetters(_SnappedProperties.Setters, SnappedStoryboard);
                _SnappedProperties.Setters.CollectionChanged += Setters_CollectionChanged;
            }
        }

        void AddSetters(IEnumerable setters, Storyboard storyboard)
        {
            if (Parent == null)
                return;
            foreach (PropertySetter setter in setters)
            {
                var animation = new ObjectAnimationUsingKeyFrames() { };
                var parent = this.GetParentOf<PhoneApplicationPage>();
                var target = parent.FindName(setter.Target) as DependencyObject;
                Storyboard.SetTarget(animation, target);
                Storyboard.SetTargetProperty(animation, new PropertyPath(setter.Property));
                //animation.SetValue(Storyboard.TargetNameProperty, setter.Target);
                animation.KeyFrames.Add(new DiscreteObjectKeyFrame()
                {
                    KeyTime = new TimeSpan(0),
                    Value = setter.Value,
                });
                storyboard.Children.Add(animation);
            }
        }

        void Setters_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
            {
                AddSetters(e.NewItems, SnappedStoryboard);
            }
        }
    }

    public class PropertySetter : DependencyObject
    {
        public object Value
        {
            get { return (object)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }
        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register("Value", typeof(object), typeof(PropertySetter), new PropertyMetadata(null));

        public string Target
        {
            get { return (string)GetValue(TargetProperty); }
            set { SetValue(TargetProperty, value); }
        }
        public static readonly DependencyProperty TargetProperty =
            DependencyProperty.Register("Target", typeof(string), typeof(PropertySetter), new PropertyMetadata(null));

        public string Property
        {
            get { return (string)GetValue(PropertyProperty); }
            set { SetValue(PropertyProperty, value); }
        }
        public static readonly DependencyProperty PropertyProperty =
            DependencyProperty.Register("Property", typeof(string), typeof(PropertySetter), new PropertyMetadata(null));
    }

    [ContentProperty("Setters")]
    public class PropertySetters : DependencyObject
    {
        private ObservableCollection<PropertySetter> _Setters = new ObservableCollection<PropertySetter>();

        public ObservableCollection<PropertySetter> Setters
        {
            get { return _Setters; }
        }

    }
}
